use colored::*;
use core::fmt;
use once_cell::sync::Lazy;
use regex::Regex;
use std::collections::HashMap;
use std::io;
use std::sync::Mutex;

static NUMBERS1: Lazy<Mutex<Vec<i32>>> = Lazy::new(|| Mutex::new(vec![10, 32, 64, 97, 11]));
static NUMBERS2: Lazy<Mutex<Vec<i32>>> = Lazy::new(|| Mutex::new(vec![10, 32, 64, 97, 11, 11]));
static NUMBERS3: Lazy<Mutex<Vec<i32>>> = Lazy::new(|| Mutex::new(vec![10, 32, 64, 97, 11, 64, 11]));
fn main() {
    println!("{}", "test_first:".green());
    let numbers = NUMBERS1.lock().unwrap();
    let mut numbers = numbers.clone();
    let result = test_first(&mut numbers);
    println!("{:#?}", result);

    let numbers = NUMBERS2.lock().unwrap();
    let mut numbers = numbers.clone();
    let result = test_first(&mut numbers);
    println!("{:#?}", result);

    let numbers = NUMBERS3.lock().unwrap();
    let mut numbers = numbers.clone();
    let result = test_first(&mut numbers);
    println!("{:#?}", result);

    println!("{}", "test_second:".green());
    let result = test_second("hello world");
    println!("{:#?}", result);
    let result = test_second("open source Application");
    println!("{:#?}", result);
    let result = test_second("中文 测试");
    println!("{:#?}", result);
    let result = test_second("中文 English にほんご 😊");
    println!("{:#?}", result);

    println!("{}", "test_third:".green());
    loop {
        println!("\nChoose an option:");
        println!("1. Add an employee to a department");
        println!("2. Get all employees in the company (sorted)");
        println!("3. Exit");

        let mut choice = String::new();
        io::stdin()
            .read_line(&mut choice)
            .expect("Failed to read input");
        let choice = choice.trim();

        match choice {
            "1" => {
                println!("Enter the command in the format 'Add [Employee] to [Department]':");
                let mut command = String::new();
                io::stdin()
                    .read_line(&mut command)
                    .expect("Failed to read input");
                let command = command.trim();

                let result = test_third(command);
                println!("{:#?}", result);
            }
            "2" => {
                let result = test_third("get all");
                println!("{:#?}", result);
            }
            "3" => {
                println!("Exiting program. Goodbye!");
                break;
            }
            _ => println!("Invalid choice. Please enter a number between 1 and 4."),
        }
    }
}

/**
给定一系列数字，使用 vector 并返回这个列表的
平均数（mean, average）、中位数（排列数组后位于中间的值）
和众数（mode，出现次数最多的值；这里哈希 map 会很有帮助）。
*/
fn test_first(numbers: &mut [i32]) -> (f64, f64, Vec<i32>) {
    let (mut mean, mut median, mut mode) = (0.0, 0.0, vec![]);

    let sum: i32 = numbers.iter().sum();
    mean = sum as f64 / numbers.len() as f64;

    numbers.sort();

    match numbers.len() & 1 {
        0 => {
            let mid1 = numbers.len() / 2 - 1;
            let mid2 = numbers.len() / 2;

            median = (numbers[mid1] as f64 + numbers[mid2] as f64) / 2.0;
        }

        1 => {
            median = numbers[numbers.len() / 2] as f64;
        }

        _ => println!("无法判断"),
    }

    let mut numbersMap = HashMap::new();

    for num in numbers {
        let count = numbersMap.entry(num).or_insert(0);
        *count += 1;
    }
    // print!("{:#?}", numbersMap);

    let max_count = numbersMap.values().cloned().max().unwrap_or(0);

    mode = numbersMap
        .into_iter()
        .filter(|&(_, count)| count == max_count && count > 1)
        .map(|(num, _)| *num)
        .collect();

    (mean, median, mode)
}

/**
将字符串转换为 Pig Latin，也就是每一个单词的
第一个辅音字母被移动到单词的结尾并增加 “ay”，所以 “first” 会变成 “irst-fay”。
元音字母开头的单词则在结尾增加 “hay”（“apple” 会变成 “apple-hay”）。牢记 UTF-8 编码！
*/
fn test_second<T: AsRef<str>>(words: T) -> String {
    let mut result_worlds = vec![];
    let vowel = ['a', 'e', 'i', 'o', 'u'];

    for word in words.as_ref().split_whitespace() {
        if let Some(first_char) = word.chars().next() {
            if vowel.contains(&first_char.to_ascii_lowercase()) {
                result_worlds.push(format!("{}-{}", word.to_string(), "hay"));
            } else if first_char.is_ascii() {
                let rest: String = word.chars().skip(1).collect();
                result_worlds.push(format!("{}-{}{}", rest, first_char.to_string(), "ay"));
            } else {
                result_worlds.push(format!("{}", word.to_string()));
            }
        }
    }
    result_worlds.join(" ")
}

/**
使用哈希 map 和 vector，
创建一个文本接口来允许用户向公司的部门中增加员工的名字。
例如，“Add Sally to Engineering” 或 “Add Amir to Sales”。
返回用户获取部门的所有员工的列表，
或者公司每个部门的所有员工按照字典序排列的列表。
*/
#[derive(Debug)]
enum ResultList {
    LIST(String, Vec<String>),
    LISTS(HashMap<String, Vec<String>>),
    None,
}

fn test_third<T: AsRef<str>>(text: T) -> ResultList {
    static EMPLOYEE_LISTS: Lazy<Mutex<HashMap<String, Vec<String>>>> =
        Lazy::new(|| Mutex::new(HashMap::new()));
    let mut employee = vec![];
    let mut department = String::new();

    let re = Regex::new(r"(?i)^add \w+ to \w+").unwrap();
    let re_get_all = Regex::new(r"(?i)^get all").unwrap();

    if re.is_match(text.as_ref()) {
        employee = vec![text.as_ref().split_whitespace().nth(1).unwrap().to_string()];
        department = text.as_ref().split_whitespace().nth(3).unwrap().to_string();
        match EMPLOYEE_LISTS.lock().unwrap().entry(department.clone()) {
            std::collections::hash_map::Entry::Occupied(mut entry) => {
                entry.get_mut().push(employee[0].clone());
                let mut befor_sorted = entry.get().to_vec();
                befor_sorted.sort_by_key(|s| s.to_lowercase());
                employee = befor_sorted;
            }

            std::collections::hash_map::Entry::Vacant(entry) => {
                entry.insert(employee.clone());
            }
        }
        return ResultList::LIST(department, employee);
    }

    if re_get_all.is_match(text.as_ref()) {
        let mut lists = EMPLOYEE_LISTS.lock().unwrap().clone();
        lists = lists
            .into_iter()
            .map(|(key, mut vec)| {
                vec.sort_by_key(|s| s.to_lowercase());
                (key, vec)
            })
            .collect();
        return ResultList::LISTS(lists);
    }

    ResultList::None
}
